package com.aixin.csopuser.service;

import com.aixin.common.exception.CustomException;
import com.aixin.csopequity.domain.ServiceLevelDef;
import com.aixin.csopequity.domain.vo.SupplierServiceVo;
import com.aixin.csopequity.repository.ServiceLevelDefRepository;
import com.aixin.csopsupplier.domain.ServiceDef;
import com.aixin.csopuser.domain.*;
import com.aixin.csopuser.domain.vo.PointHistory;
import com.aixin.csopuser.mapper.CustomerUserMapper;
import com.aixin.csopuser.mapper.SupplierCustMapper;
import com.aixin.csopuser.model.*;
import com.aixin.csopuser.repository.*;
import com.aixin.csopuser.utils.ResponseUtils;
import com.aixin.csopuser.utils.Util;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.query.QueryUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Predicate;
import javax.transaction.Transactional;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class CustomerService {

    @Autowired
    CustomerRepository customerRepository;
    @Autowired
    ServicesHistoryRepository servicesHistoryRepository;
    @Autowired
    SupplierCustMapper supplierCustMapper;
    @Autowired
    CustomerOwnedRepository customerOwnedRepository;
    @Autowired
    PolicyRepository policyRepository;
    @Autowired
    CustomerUserMapper customerUserMapper;
    @Autowired
    CustomerEquityRepository customerEquityRepository;
    @Resource
    private ServiceLevelDefRepository serviceLevelDefRepository;
    @Autowired
    private EntityManager entityManager;
    @Autowired
    private ServiceDefineRepository serviceDefineRepository;
    @Autowired
    private AgentInfoRepository agentInfoRepository;
    @Autowired
    private ServiceConsumeHistoryRepository serviceConsumeHistoryRepository;
    @Autowired
    private CustomerServiceConsumeRepository customerServiceConsumeRepository;

    public PageInfo<CustomerDomain> downloadCustomerDomain(CustomerModel model, String deptCode) {
        return getCustomerDomain(model, deptCode, false, 1, 9999999);
    }

    public PageInfo<CustomerDomain> getCustomerDomain(CustomerModel model, String deptCode, Boolean needAgent, int pageNum, int pageSize) {

        StringBuilder queryUrl = new StringBuilder();
        StringBuilder countUrl = new StringBuilder();
        StringBuilder sb = new StringBuilder();
        HashMap<String, Object> argMap = new HashMap<>();
        argMap.put("deptCode", deptCode);
        if (StringUtils.isEmpty(model.getEquityType())
                && StringUtils.isEmpty(model.getEquityLevelID())
                && StringUtils.isEmpty(model.getEquityID())
                && StringUtils.isEmpty(model.getServiceID())) {
            // 如果不包含权益条件，直接查询客户表
            sb.append("select c.* from customer c where left(c.agentAgency,").append(deptCode.length()).append(")=:deptCode");
            if (!StringUtils.isEmpty(model.getCustName())) {
                sb.append(" and c.custName like '%").append(model.getCustName()).append("%' ");
            }
            if (!StringUtils.isEmpty(model.getCertID())) {
                sb.append(" and c.certID like '%").append(model.getCertID()).append("%' ");
            }
            queryUrl = sb;
            countUrl.append("select count(0) from (").append(queryUrl).append(") cc");
        } else {
            // 如果包含权益或服务条件，先查用户权益表
//            queryUrl = "select cc.* from customer cc where cc.customerID in (";
            queryUrl.append("select cc.* from customer cc where left(cc.agentAgency,").append(deptCode.length()).append(")=:deptCode");
            countUrl.append("select count(0) from customer cc where left(cc.agentAgency,").append(deptCode.length()).append(")=:deptCode");

            if (!StringUtils.isEmpty(model.getCustName())) {
                queryUrl.append(" and cc.custName like '%").append(model.getCustName()).append("%' ");
                countUrl.append(" and cc.custName like '%").append(model.getCustName()).append("%' ");
            }
            if (!StringUtils.isEmpty(model.getCertID())) {
                queryUrl.append(" and cc.certID like '%").append(model.getCertID()).append("%' ");
                countUrl.append(" and cc.certID like '%").append(model.getCertID()).append("%' ");
            }
            queryUrl.append(" and cc.customerID in (");
            countUrl.append(" and cc.customerID in (");

            sb.append("select distinct ce.customerID from customerequity ce where 1=1 ");
            if (!StringUtils.isEmpty(model.getEquityType())) {
                sb.append(" and ce.equitytype=:equityType ");
                argMap.put("equityType", model.getEquityType());
            }
            if (!StringUtils.isEmpty(model.getEquityID())) {
                sb.append(" and ce.equityid=:equityID ");
                argMap.put("equityID", model.getEquityID());
            }
            if (!StringUtils.isEmpty(model.getEquityLevelID())) {
                sb.append(" and ce.custlevelid=:equityLevelID ");
                argMap.put("equityLevelID", model.getEquityLevelID());
            }
            if (!StringUtils.isEmpty(model.getServiceID())) {
                sb.append(" and exists (select 0 from serviceleveldef sld where sld.serviceid=:serviceID and sld.equityid=ce.equityid and sld.equitylevelid=ce.custlevelid)");
                argMap.put("serviceID", model.getServiceID());
            }

            queryUrl.append(sb).append(")");
            countUrl.append(sb).append(")");
        }

        Query query = entityManager.createNativeQuery(queryUrl.toString(), CustomerDomain.class);
        for (Map.Entry<String, Object> entry : argMap.entrySet()) {
            query.setParameter(entry.getKey(), entry.getValue());
        }
        query.setFirstResult((pageNum - 1) * pageSize);
        query.setMaxResults(pageSize);
        List<CustomerDomain> resultList = query.getResultList();

        // 设置agentInfo数据
        if (needAgent) {
            resultList.forEach(c -> {
                agentInfoRepository.findByAgentCode(c.getAgentCode()).ifPresent(a -> c.setAgentInfo(a));
            });
        }

        query = entityManager.createNativeQuery(countUrl.toString());
        for (Map.Entry<String, Object> entry : argMap.entrySet()) {
            query.setParameter(entry.getKey(), entry.getValue());
        }
        BigInteger total = (BigInteger) query.getSingleResult();
        return ResponseUtils.makePageInfo(total.longValue(), pageNum, pageSize, resultList);
    }

//    public PageInfo<SupplierCustomerDomain> downloadCustomerBySupplier(SupplierCustomerModel supplier) {
//        return getCustomerBySupplier(supplier, false, 1, 9999999);
//    }

    public PageInfo<SupplierCustomerDomain> getCustomerBySupplier(SupplierCustomerModel supplier, Boolean needSupplier, int pageNum, int pageSize) {

//        supplier.setSupplierID(null);
//        HashMap<String, Object> argMap = new HashMap<>();//用于封装参数

        List<String> idList = new ArrayList<>();
        if (!StringUtils.isEmpty(supplier.getSupplierID()) || !StringUtils.isEmpty(supplier.getServiceID())) {
            // 如果参数中包含supplierID，则先查找对应equityID
            List<ServiceLevelDef> equityList = serviceLevelDefRepository.findEquities(supplier.getSupplierID(), supplier.getServiceID());
//            List<CustomerEquity> equityIDList = customerEquityRepository.getEquityLevelIDBySupplier(supplier.getSupplierID(), supplier.getServiceID());
            idList = equityList.stream().map(ServiceLevelDef::getEquityID).collect(Collectors.toList());
            if (idList.size() == 0) {
                PageInfo pi = new PageInfo();
                pi.setList(null);
                return pi;
            }
        }

        PageRequest pr = PageRequest.of(pageNum - 1, pageSize);
        //TODO idList去重
//        String useIdList = idList == null ? null : "";
//        String idString = null;
        String useIdList = "true";
        if (idList.size() == 0) {
            useIdList = null;
//            idList = new ArrayList<>();
            idList.add("empty");
//            idString = "";
//            for (int i = 0; i < idList.size(); i++) {
//                if (i > 0) {
//                    idString += ",";
//                }
//                idString += "'" + idList.get(i) + "'";
//            }
        } else {
            ArrayList<String> newList = new ArrayList<>();
            idList.forEach(id -> {
                if (!newList.contains(id)) {
                    newList.add(id);
                }
            });
            idList = newList;
        }

        Page<SupplierCustomerDomain> page = customerEquityRepository.getCustomerEquityBySupplier(supplier.getCustName(), supplier.getCertID(), useIdList, idList, pr);
        List<SupplierCustomerDomain> retList = page.getContent();
        if (retList.size() > 0 && needSupplier) {
            // 设置supplierID
            if (!StringUtils.isEmpty(supplier.getSupplierID())) {
                // 从查询参数中设置
                retList.forEach(domain -> domain.setSupplierID(supplier.getSupplierID()));
            } else {
                // 从数据库中查找对应的supplierID
                HashMap<String, String> idMap = new HashMap<>();
                retList.forEach(domain -> {
                    idMap.putIfAbsent(domain.getEquityLevelID(), "");
                });
                List<String> levelIdList = new ArrayList(idMap.keySet());

//                List<String> levelIdList = retList.stream().map(SupplierCustomerDomain::getEquityLevelID).collect(Collectors.toList());
                List<SupplierServiceVo> supplierServiceVoList = serviceLevelDefRepository.getServiceDefByEquityLevelIDList(levelIdList);
                for (SupplierServiceVo vo : supplierServiceVoList) {
                    retList.stream().forEach(domain -> {
                        if (vo.getEquityLevelID().equals(domain.getEquityLevelID())) {
                            domain.setSupplierID(vo.getSupplierID());
                        }
                    });
                }
            }
        }

        // 设置usedNum
//        retList.stream().forEach(domain -> {
//            customerOwnedRepository.findByCustomerIDAndPolicyID(domain.getCustomerID(), domain.getPolicyNumber())
//            .ifPresent(owned -> domain.setUsedNumber(owned.getUsedNum()));
//        });

        PageInfo info = ResponseUtils.makePageInfo(page, retList);
        return info;
    }

    public List getPoint(String customerID) {
        return customerRepository.getPoint(customerID);
    }

    public List<Map> getCustomerPointHistory(String customerID) {
        List ret = customerRepository.getCustomerPointHistory(customerID);
        return ret;
    }

    public List<Map<String, String>> getEquity(String customerID) {
        return customerRepository.getEquity(customerID);
    }

    public List<PolicyDomain> getPolicy(String customerID) {
        return policyRepository.findAllByCustomerID(customerID);
    }

    public List<Map<String, String>> getService(CustServiceModel custServiceModel) {
        return customerRepository.getService(custServiceModel.getCustomerID(), custServiceModel.getEquityID(), custServiceModel.getServiceID());
    }

    public List<CustomerOwnedServices> getServicesByPolicyNumber(String policyNumber) {
        // 先通过policyNumber查询客户权益，获取对应的权益信息
        List<CustomerEquity> equityList = customerEquityRepository.findAllByPolicyNumber(policyNumber);
        if (equityList.size() == 0) {
            return null;
        }

        HashMap<String, CustomerOwnedServices> serviceMap = new HashMap<>();

        for (CustomerEquity equity : equityList) {
            // 遍历所有权益，获取对应的服务流水数据
            List<CustomerOwnedServices> services = customerOwnedRepository.findAllByCustomerIDAndEquityIDAndEquityLevelIDOrderByCustServiceNumAscCreateTimeDesc(
                    equity.getCustomerID(), equity.getEquityID(), equity.getCustLevelID());
            for (int i = 0; i < services.size(); i++) {
                CustomerOwnedServices s = services.get(i);
                // 服务排重，相同的服务只记录第一条
                serviceMap.putIfAbsent(s.getCustServiceNum(), s);
            }
        }

        return new ArrayList<>(serviceMap.values());
    }

    public List<Map<String, String>> getServicesHistory(ServicesHistoryModel servicesHistoryModel) {
        if ("".equals(servicesHistoryModel.getSupplierID())) {
            servicesHistoryModel.setSupplierID(null);
        }
        return servicesHistoryRepository.getServicesHistory(servicesHistoryModel.getCustomerID(), servicesHistoryModel.getEquityID(), servicesHistoryModel.getEquityLevelID(), servicesHistoryModel.getSupplierID());
    }

    @Transactional
    public String saveServicesHistory(ServicesHistory model) {
        CustomerOwnedServices customerOwnedServices = new CustomerOwnedServices();
        customerOwnedServices.setCustomerID(model.getCustomerID());
        customerOwnedServices.setEquityID(model.getEquityID());
        customerOwnedServices.setEquityLevelID(model.getEquityLevelID());
        CustomerOwnedServices customerOwned = customerUserMapper.getOwnedService(customerOwnedServices);
        if (null != customerOwned) {
            model.setCustServiceNum(customerOwned.getCustServiceNum());
        } else {
            customerOwnedServices.setCreateTime(Instant.now());
            customerOwnedServices.setCustServiceNum(Util.getUUID());
            customerOwnedRepository.save(customerOwnedServices);
            model.setCustServiceNum(customerOwnedServices.getCustServiceNum());

        }
        ServiceConsumeHistory serviceConsumeHistory = new ServiceConsumeHistory();
        serviceConsumeHistory.setHistoryNumber(Util.getUUID());
        serviceConsumeHistory.setCustomerID(model.getCustomerID());
        serviceConsumeHistory.setEquityID(model.getEquityID());
        serviceConsumeHistory.setEquityLevelID(model.getEquityLevelID());
        serviceConsumeHistory.setSupplierID(model.getSupplierID());
        serviceConsumeHistory.setServiceID(model.getServiceID());
        serviceConsumeHistory.setConsumeTime(model.getConsumeTime());
        serviceConsumeHistory.setCreateTime(Util.getNowDate());
        serviceConsumeHistory.setNumConsumed(model.getNumConsumed());
        serviceConsumeHistory.setRemarks(model.getRemarks());
        servicesHistoryRepository.save(serviceConsumeHistory);
        updateConsumedNum(model.getCustServiceNum(), model.getCustomerID(), model.getSupplierID(), model.getServiceID(), model.getNumConsumed());

        saveCustomerServiceConsume(model.getCustomerID(), model.getServiceID(), model.getEquityID(), model.getEquityLevelID(), model.getConsumeTime(), 0);

        return serviceConsumeHistory.getHistoryNumber();
    }

    // 保存服务核销汇总数据
    private void saveCustomerServiceConsume(String customerID, String serviceID, String equityID, String equityLevelID, String consumeTime, Integer addNumber) {
        // 更新用户的权益使用次数
        CustomerServiceConsume consume = customerServiceConsumeRepository
                .findByCustomerIDAndServiceID(customerID, serviceID)
                .orElse(new CustomerServiceConsume());
        if (consume.getId() == null) {
            consume.setCreateTime(Instant.now());
            consume.setCustomerID(customerID);
            consume.setEquityID(equityID);
            consume.setEquityLevelID(equityLevelID);
            consume.setServiceID(serviceID);
        }
        consume.setUpdateTime(Instant.now());

        List<ServiceConsumeHistory> historyList = servicesHistoryRepository.findAllByCustomerIDAndEquityIDAndEquityLevelID(customerID, equityID, equityLevelID);
        Long sum = 0L;
        String lastUse = "";
        for (ServiceConsumeHistory history : historyList) {
            if (!serviceID.equals(history.getServiceID())) {
                continue;
            }
            sum += history.getNumConsumed();
            if (lastUse.compareTo(history.getConsumeTime()) < 0) {
                lastUse = history.getConsumeTime();
            }
        }
        consume.setUsedCount(sum + addNumber);
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
        try {
            consume.setLastUseDate(LocalDate.parse(consumeTime, dateTimeFormatter));
        } catch (Exception e) {
            consume.setLastUseDate(LocalDate.now());
        }
        customerServiceConsumeRepository.save(consume);
    }

    @Transactional
    public String updateServicesHistory(ServicesHistory model) {
        ServiceConsumeHistory serviceConsumeHistory;
        serviceConsumeHistory = servicesHistoryRepository.getConsumedByHistoryNumber(model.getHistoryNumber());
        int consumedNum = serviceConsumeHistory.getNumConsumed();
        consumedNum = model.getNumConsumed() - consumedNum;
        servicesHistoryRepository.updateConsumeHistory(model.getHistoryNumber(), model.getConsumeTime(), new String(model.getRemarks()), model.getNumConsumed(), model.getServiceID());
        updateConsumedNum(model.getCustServiceNum(), model.getCustomerID(), model.getSupplierID(), model.getServiceID(), consumedNum);

        saveCustomerServiceConsume(model.getCustomerID(), model.getServiceID(), model.getEquityID(), model.getEquityLevelID(), model.getConsumeTime(), consumedNum);

        return model.getHistoryNumber();
    }

    public void updateConsumedNum(String custServiceNum, String customerID, String supplierID, String serviceID, int consumedNum) {
        servicesHistoryRepository.updateSupplierDef(consumedNum, Util.getNowDate(), supplierID);
        servicesHistoryRepository.updateServiceDef(consumedNum, Util.getNowDate(), serviceID);
        servicesHistoryRepository.updateCustOwnedservice(consumedNum, custServiceNum, Util.getNowDate());
    }

    public CustomerDomain getCustomer(String customerID) {
        return customerRepository.findByCustomerID(customerID).orElse(null);
    }

    public CustomerDomain getFullInfo(String customerID) {

        CustomerDomain customer = customerRepository.findByCustomerID(customerID).orElse(null);
        agentInfoRepository.findByAgentCode(customer.getAgentCode()).ifPresent(a -> customer.setAgentInfo(a));

        // 为用户权益查询其拥有的服务项
        List<CustomerEquity> equities = new ArrayList<>(customer.getCustomerEquities());
        equities.forEach(customerEquity -> {
            List<ServiceDef> services = serviceDefineRepository.findEquityServices(customerEquity.getEquityID(), customerEquity.getCustLevelID());

            // 添加权益对应服务
            for (ServiceDef service : services) {
                if (service.getTotalNumber() > 0) {
                    customerServiceConsumeRepository.findByCustomerIDAndServiceID(customerID, service.getServiceID())
                            .ifPresent(consume -> {
                                service.setLastUseDate(consume.getLastUseDate());
                                service.setUsedCount(consume.getUsedCount().intValue());
                            });
//                    // 如果可用次数>0，则查找已用服务的次数
//                    List<CustomerOwnedServices> usedServices = customerOwnedRepository.findAllByCustServiceNumOrderByCreateTimeDesc(service.getServiceID());
//                    service.setUsedCount(usedServices.size());
//                    if (usedServices.size() > 0) {
//                        service.setLastUseTime(usedServices.get(0).getUseTime());
//                    }
                }
            }
            customerEquity.setServices(services);
            // 添加保单权益对应保单数据
            if (!StringUtils.isEmpty(customerEquity.getPolicyNumber())) {
                List<PolicyDomain> policyList = policyRepository.findByPolicyNumber(customerEquity.getPolicyNumber());
                if (policyList.size() > 0) {
                    customerEquity.setPolicy(policyList.get(0));
                }
            }

            // 添加权益服务使用记录
            List<ServiceConsumeHistory> historyList = serviceConsumeHistoryRepository
                    .findAllByCustomerIDAndEquityIDAndEquityLevelIDOrderByCreateTimeDesc(customerID, customerEquity.getEquityID(), customerEquity.getCustLevelID());
            customerEquity.setConsumeHistories(historyList);
        });

        return customer;
    }

    public List<ServiceConsumeHistory> findServicesConsumeHistory(ServicesHistoryModel model) {
        List<ServiceConsumeHistory> resultList = servicesHistoryRepository.findAll(((root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("customerID"), model.getCustomerID()));

            if (!StringUtils.isEmpty(model.getEquityID())) {
                list.add(criteriaBuilder.equal(root.get("equityID"), model.getEquityID()));
            }

            if (!StringUtils.isEmpty(model.getEquityLevelID())) {
                list.add(criteriaBuilder.equal(root.get("equityLevelID"), model.getEquityLevelID()));
            }

            if (!StringUtils.isEmpty(model.getSupplierID())) {
                list.add(criteriaBuilder.equal(root.get("supplierID"), model.getSupplierID()));
            }

            if (!StringUtils.isEmpty(model.getServiceID())) {
                list.add(criteriaBuilder.equal(root.get("serviceID"), model.getServiceID()));
            }
            query.orderBy(QueryUtils.toOrders(new Sort(Sort.Direction.DESC, "createTime"), root, criteriaBuilder));

            return query.where(list.toArray(new Predicate[list.size()])).getRestriction();
        }));

        return resultList;
    }
}
